﻿using System;
using Vjezbe2;
using Moq;
using NUnit.Framework;
using System.Collections.Generic;

namespace Vjezbe2.Test
{
    [TestFixture]
    public class TopUpServiceTest
    {
        ITopUpService topUpService;
        ITopUpDataService dataService;

        readonly int accountId = 1;
        
        [SetUp]
        public void setupTest()
        {
            dataService = Mock.Of<ITopUpDataService>();
            topUpService = new TopUpService(dataService);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void should_throw_if_argument_is_null()
        {
            topUpService.TopUp(null);
            Assert.Fail("expecting ArgumentNullException");
        }

        [Test]
        public void should_add_additional_10_if_amount_lessThanOrEqual_50()
        {
            int amount = 50;
            TopUpRequest request = new TopUpRequest(accountId, amount);

            topUpService.TopUp(request);

            int expectedAmount = amount + 10;
            Mock.Get(dataService).Verify(ds => ds.AddAmount(accountId, expectedAmount));
        }

        [Test]
        public void should_add_additional_20_if_amount_greaterThan_50()
        {
            int amount = 51;
            TopUpRequest request = new TopUpRequest(accountId, amount);

            topUpService.TopUp(request);

            int expectedAmount = amount + 20;
            Mock.Get(dataService).Verify(ds => ds.AddAmount(accountId, expectedAmount));
        }

        [Test]
        public void should_retry_3_times_if_data_service_throws_exception()
        {
            Mock.Get(dataService).SetupSequence<ITopUpDataService, int>(ds => ds.AddAmount(It.IsAny<int>(), It.IsAny<int>()))
                .Throws(new Exception("prvi exception"))
                .Throws(new Exception("drugi exception"))
                .Throws(new Exception("treci exception"))
                .Throws(new Exception("nikad ne bi smjelo doci do ovog exceptiona"));

            int amount = 100;
            TopUpRequest request = new TopUpRequest(accountId, amount);

            try
            {
                topUpService.TopUp(request);
                Assert.Fail("treci exception expected");
            }
            catch (Exception e)
            {
                Assert.AreEqual("treci exception", e.Message);
            }

        }

        [Test]
        public void should_not_throw_TimeoutException()
        {
            Mock.Get(dataService).SetupSequence<ITopUpDataService, int>(ds => ds.AddAmount(It.IsAny<int>(), It.IsAny<int>()))
                .Throws(new TimeoutException("prvi exception"))
                .Throws(new TimeoutException("drugi exception"))
                .Throws(new TimeoutException("treci exception"))
                .Throws(new Exception("nikad ne bi smjelo doci do ovog exceptiona"));

            try
            {
                topUpService.TopUp(new TopUpRequest(accountId, 1));
            }
            catch
            {
                Assert.Fail("exception is not expected");
            }
        }

        [Test]
        public void should_rethrow_ArithmeticException()
        {
            Mock.Get(dataService).SetupSequence<ITopUpDataService, int>(ds => ds.AddAmount(It.IsAny<int>(), It.IsAny<int>()))
                .Throws(new ArithmeticException("prvi exception"))
                .Throws(new ArithmeticException("drugi exception"))
                .Throws(new ArithmeticException("treci exception"))
                .Throws(new ArithmeticException("nikad ne bi smjelo doci do ovog exceptiona"));

            try
            {
                topUpService.TopUp(new TopUpRequest(accountId, 1));
                Assert.Fail("expecting exception");
            }
            catch(ArithmeticException e)
            {
                Assert.AreEqual("treci exception", e.Message);
            }
        }



    }
}
